﻿#region Using References

using System.Diagnostics.CodeAnalysis;
using System.IO;
using Beaker.OpenCube.IO;
using Beaker.OpenCube.Specs.Builders;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace Beaker.OpenCube.Specs.IO
{
	[ExcludeFromCodeCoverage]
	[TestClass]
	public class BigEndianBinaryReaderSpecs
	{
		[TestMethod]
		public void ReadByte()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0xa5 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			byte data = reader.ReadByte();

			// assert
			data.Should().Be( 0xa5 );
		}

		[TestMethod]
		public void ReadSignedByte()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (sbyte)-0x25 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			sbyte data = reader.ReadSByte();

			// assert
			data.Should().Be( -0x25 );
		}

		[TestMethod]
		public void ReadShort()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0x6a ).Append( (byte)0x24 )  // write in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			short data = reader.ReadInt16();

			// assert
			data.Should().Be( 0x6a24 );
		}

		[TestMethod]
		public void ReadUnsignedShort()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0xf6 ).Append( (byte)0x24 )  // write in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			ushort data = reader.ReadUInt16();

			// assert
			data.Should().Be( 0xf624 );
		}

		[TestMethod]
		public void ReadSignedInt24()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0x0d ).Append( (byte)0x1e ).Append( (byte)0x75 )  // write in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			int data = reader.ReadInt24();

			// assert
			data.Should().Be( 0xd1e75 );
		}

		[TestMethod]
		public void ReadSignedInt24ShouldExtendSignCorrect()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0xff ).Append( (byte)0xff ).Append( (byte)0xdd )  // write -35 in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			int data = reader.ReadInt24();

			// assert
			data.Should().Be( -35 );
		}

		[TestMethod]
		public void ReadSignedUnsignedInt24()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0x0d ).Append( (byte)0x1e ).Append( (byte)0x75 )  // write in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			uint data = reader.ReadUInt24();

			// assert
			data.Should().Be( 0xd1e75 );
		}

		[TestMethod]
		public void ReadSignedUnsignedInt24ShouldNotExtendSign()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0xff ).Append( (byte)0xff ).Append( (byte)0xdd )  // write -35 in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			uint data = reader.ReadUInt24();

			// assert
			data.Should().Be( 0xffffdd );
		}

		[TestMethod]
		public void ReadInt()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0x7a ).Append( (byte)0xc3 ).Append( (byte)0x02 ).Append( (byte)0xfe )  // write in big endian format
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			int data = reader.ReadInt32();

			// assert
			data.Should().Be( 0x7ac302fe );
		}

		[TestMethod]
		public void ReadUnsignedInt()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					.Append( (byte)0x7a ).Append( (byte)0xc3 ).Append( (byte)0x02 ).Append( (byte)0xfe )  // write in big 
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			uint data = reader.ReadUInt32();

			// assert
			data.Should().Be( 0x7ac302fe );
		}

		[TestMethod]
		public void ReadLong()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
				// write in big endian format
					.Append( (byte)0x8a ).Append( (byte)0xc3 ).Append( (byte)0x02 ).Append( (byte)0xfe )
					.Append( (byte)0xe8 ).Append( (byte)0x36 ).Append( (byte)0x3e ).Append( (byte)0x10 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			long data = reader.ReadInt64();

			// assert
			data.Should().Be( -8447905182176100848 );
		}

		[TestMethod]
		public void ReadUnsignedLong()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
				// write in big endian format
					.Append( (byte)0x8a ).Append( (byte)0xc3 ).Append( (byte)0x02 ).Append( (byte)0xfe )
					.Append( (byte)0xe8 ).Append( (byte)0x36 ).Append( (byte)0x3e ).Append( (byte)0x10 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			ulong data = reader.ReadUInt64();

			// assert
			data.Should().Be( 0x8ac302fee8363e10 );
		}

		[TestMethod]
		public void ReadSingle()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
					// write in big endian format
					.Append( (byte)0x3f ).Append( (byte)0x80 ).Append( (byte)0x00 ).Append( (byte)0x00 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			float data = reader.ReadSingle();

			// assert
			data.Should().Be( 1f );
		}

		[TestMethod]
		public void ReadDouble()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
				// write in big endian format
					.Append( (byte)0x3f ).Append( (byte)0xf0 ).Append( (byte)0x00 ).Append( (byte)0x00 )
					.Append( (byte)0x00 ).Append( (byte)0x00 ).Append( (byte)0x00 ).Append( (byte)0x00 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			double data = reader.ReadDouble();

			// assert
			data.Should().Be( 1d );
		}

		[TestMethod]
		public void ReadByteArray()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
				// write in big endian format
					.Append( (byte)0x8a ).Append( (byte)0xc3 ).Append( (byte)0x02 ).Append( (byte)0xfe )
					.Append( (byte)0xe8 ).Append( (byte)0x36 ).Append( (byte)0x3e ).Append( (byte)0x10 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			byte[] data = reader.ReadBytes( 8 );

			// assert
			data.Should().Equal( new byte[] { 0x8a, 0xc3, 0x02, 0xfe, 0xe8, 0x36, 0x3e, 0x10 } );
		}

		[TestMethod]
		public void ReadSByteArray()
		{
			// arrange
			Stream stream =
				new NbtStreamBuilder()
				// write in big endian format
					.Append( (byte)0x8a ).Append( (byte)0xc3 ).Append( (byte)0x02 ).Append( (byte)0xfe )
					.Append( (byte)0xe8 ).Append( (byte)0x36 ).Append( (byte)0x3e ).Append( (byte)0x10 )
					.Build();
			var reader = new BigEndianBinaryReader( stream );

			// act
			sbyte[] data = reader.ReadSBytes( 8 );

			// assert
			data.Should().Equal( new sbyte[] { -118, -61, 2, -2, -24, 54, 62, 16 } );
		}
	}
}
